/*
 * OperationExpression.h
 *
 *  Created on: 01.04.2014
 *      Author: Nicolas
 */

#ifndef _SOLVER_OPERATIONEXPRESSION_H
#define _SOLVER_OPERATIONEXPRESSION_H

#include "Expression.h"


namespace solver
{
	class TermTemplate;

	class TermExpression;
	class AdditionExpression;
	class SubtractionExpression;
	class MultiplicationExpression;
	class DivisionExpression;
	class PowerExpression;
}


class solver::TermTemplate
{
	std::vector<std::string> operators;

	const TermTemplate* subTemplate;

	static const TermTemplate equation;
	static const TermTemplate addition;
	static const TermTemplate multiplication;
	static const TermTemplate power;

public:
	TermTemplate(void);

	/**
	 * creates a new TermTemplate with the given operators
	 *
	 * \param operators pointer to the operator array
	 * \param nOperators the amount of operators
	 */
	TermTemplate(std::string* operators, unsigned int nOperators);

	/**
	 * creates a new TermTemplate with the given operators and
	 * sets a subTemplate
	 *
	 * \param operators
	 * \param nOperators
	 * \param subTemplate
	 */
	TermTemplate(std::string* operators, unsigned int nOperators,
			const TermTemplate* subTemplate);

	/**
	 * determines, if an operator is part of this TermTemplate
	 *
	 * \param op the operator string
	 * \return true, if the operator is part of this TermTemplate
	 */
	bool operatorMatches(const std::string& op) const;

	/**
	 * \return a description text
	 */
	std::string toString(void) const;

	/**
	 * \return a new term expression of this TermTokenBlock
	 */
	Expression* createTermExpression(const TermTokenBlock& ttb) const;


	static const TermTemplate& getEquation(void);
	static const TermTemplate& getAddition(void);
	static const TermTemplate& getMultiplication(void);
	static const TermTemplate& getPower(void);
	static const TermTemplate& getBaseTermTemplate(void);
};


class solver::TermExpression :
		public Expression
{
public:
	const Expression* a;
	const Expression* b;
public:
	TermExpression(void);
	TermExpression(const Expression* a, const Expression* b);
	virtual ~TermExpression(void);

	virtual const Expression* evaluate(void) const = 0;
	virtual const std::string& getOperatorSymbol(void) const = 0;
	virtual std::string getAsString(void) const;
	virtual std::string toString(void) const;
};


class solver::AdditionExpression :
		public TermExpression
{
	static const std::string operatorSymbol;
public:
	AdditionExpression(void);
	AdditionExpression(const Expression* a, const Expression* b);
	virtual ~AdditionExpression(void);

	virtual const Expression* evaluate(void) const;
	virtual const std::string& getOperatorSymbol(void) const;
};


class solver::SubtractionExpression :
		public TermExpression
{
	static const std::string operatorSymbol;
public:
	SubtractionExpression(void);
	SubtractionExpression(const Expression* a, const Expression* b);
	virtual ~SubtractionExpression(void);

	virtual const Expression* evaluate(void) const;
	virtual const std::string& getOperatorSymbol(void) const;
};


class solver::MultiplicationExpression :
		public TermExpression
{
	static const std::string operatorSymbol;
public:
	MultiplicationExpression(void);
	MultiplicationExpression(const Expression* a, const Expression* b);
	virtual ~MultiplicationExpression(void);

	virtual const Expression* evaluate(void) const;
	virtual const std::string& getOperatorSymbol(void) const;
};


/**
 * \brief representation of a fraction
 *
 * This class works as a representation for fractions. It sometimes can't
 * be evaluated exactly (when working with whole numbers).
 */
class solver::DivisionExpression :
		public TermExpression
{
	static const std::string operatorSymbol;
public:
	DivisionExpression(void);
	DivisionExpression(const Expression* a, const Expression* b);
	virtual ~DivisionExpression(void);

	virtual const Expression* evaluate(void) const;
	virtual const std::string& getOperatorSymbol(void) const;

	virtual const Expression* add(const Expression* b) const;
	virtual const Expression* sub(const Expression* b) const;
	virtual const Expression* mult(const Expression* b) const;
	virtual const Expression* div(const Expression* b) const;
	virtual const Expression* pow(const Expression* b) const;

	virtual std::string toString(void) const;
};


class solver::PowerExpression :
		public TermExpression
{
	static const std::string operatorSymbol;
public:
	PowerExpression(void);
	PowerExpression(const Expression* a, const Expression* b);
	virtual ~PowerExpression(void);

	virtual const Expression* evaluate(void) const;
	virtual const std::string& getOperatorSymbol(void) const;
};


#endif // _SOLVER_OPERATIONEXPRESSION_H
